package com.ztsoft.user.service.project.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ztsoft.user.common.exception.CustomException;
import com.ztsoft.user.mapper.project.ConstructionMapper;
import com.ztsoft.user.pojo.entity.project.ChooseConstruction;
import com.ztsoft.user.pojo.entity.project.Construction;
import com.ztsoft.user.pojo.enums.ResultCode;
import com.ztsoft.user.pojo.vo.PageData;
import com.ztsoft.user.pojo.vo.PageInfo;
import com.ztsoft.user.pojo.vo.project.ConstructionVo;
import com.ztsoft.user.pojo.vo.project.UnifiedForms;
import com.ztsoft.user.service.project.ChooseConstructionService;
import com.ztsoft.user.service.project.ConstructionService;
import com.ztsoft.user.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.*;

@Slf4j
@Service
public class ConstructionServiceImpl extends ServiceImpl<ConstructionMapper, Construction> implements ConstructionService {

    @Value("${file.dataExcelFile}")
    private String dataExcelFile;

    @Resource
    private ChooseConstructionService chooseConstructionService;

    @Override
    public void exportTemplate(HttpServletResponse response) {
        String fileName = "constructionTemplate.xlsx";

        // 下载
        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            InputStream inputStream = FileUtils.getResources(fileName);
            EasyExcelFactory.write(response.getOutputStream()).needHead(false).withTemplate(inputStream).sheet(0).doWrite(Collections.emptyList());
        } catch (Exception e) {
            log.error(e.toString());
            throw new CustomException(ResultCode.ABNORMAL.getMsg(), ResultCode.ABNORMAL.getCode());
        }
    }

    @Override
    public Result<Object> parseUpLoadFile(String chooseId, MultipartFile fileList) {
        List<String> fileNames = UploadFilesUtils.uploadFiles(fileList);

        List<Construction> list = new ArrayList<>();
        // 校验
        for (String fileName : fileNames) {
            String filePath = dataExcelFile + fileName;
            EasyExcelFactory.read(filePath, ConstructionVo.class, new AnalysisEventListener<ConstructionVo>() {
                @Override
                public void invoke(ConstructionVo constructionVo, AnalysisContext analysisContext) {
                    Construction construction = new Construction();
                    BeanUtil.copyProperties(constructionVo, construction);
                    list.add(construction);
                }

                @Override
                public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                    log.error("Excel信息提取成功！");
                }
            }).sheet().doRead();
            if (!checkIdCard(list)) {
                log.error("有身份证号码信息输入出错！");
                return Result.returnMsg("有身份证号码信息输入出错，请检查后重新导入！", ResultCode.FAILED.getCode());
            }
            if (!checkSex(list)) {
                log.error("有性别信息输入出错！");
                return Result.returnMsg("有性别信息输入出错，请检查后重新导入！", ResultCode.FAILED.getCode());
            }
            if (!checkPhone(list)) {
                log.error("有联系电话信息输入出错！");
                return Result.returnMsg("有联系电话信息输入出错，请检查后重新导入！", ResultCode.FAILED.getCode());
            }

            // 写入数据库
            ExcelReader excelReader = EasyExcelFactory.read(filePath, ConstructionVo.class, new ConstructionListener(this, chooseConstructionService, chooseId)).headRowNumber(1).build();
            ReadSheet sheet = EasyExcelFactory.readSheet(0).build();
            excelReader.read(sheet);
            excelReader.finish();
        }

        return Result.success();
    }

    @Override
    public Result<Object> getConstruction(String chooseId, Integer pageSize, Integer currentPage) {
        List<ChooseConstruction> chooseConstructionList = chooseConstructionService.list(new QueryWrapper<ChooseConstruction>().eq("choose_id", chooseId));

        List<String> ids = new ArrayList<>();
        for (ChooseConstruction chooseConstruction : chooseConstructionList) {
            ids.add(chooseConstruction.getConstructionId());
        }

        if (ids.isEmpty()) {
            return Result.success(new PageData(Collections.emptyList(), new PageInfo(pageSize, currentPage, 0)));
        }

        List<Construction> construction = baseMapper.getConstruction(ids, currentPage - 1, pageSize);
        int count = baseMapper.getCount(ids);

        return Result.success(new PageData(construction, new PageInfo(pageSize, currentPage, count)));
    }

    @Override
    public Result<Object> unified(UnifiedForms<Construction> unifiedForms, String chooseId) {
        try {
            Construction[] insertRecords = unifiedForms.getInsertRecords();
            Construction[] removeRecords = unifiedForms.getRemoveRecords();
            Construction[] updateRecords = unifiedForms.getUpdateRecords();

            if (Objects.nonNull(insertRecords) && insertRecords.length != 0) {
                saveConstruction(chooseId, insertRecords);
            }
            if (Objects.nonNull(removeRecords) && removeRecords.length != 0) {
                deleteConstruction(chooseId, removeRecords);
            }
            if (Objects.nonNull(updateRecords) && updateRecords.length != 0) {
                updateConstruction(updateRecords);
            }
            return Result.success();
        } catch (Exception e) {
            log.info("出现异常", e);
            return Result.error();
        }
    }

    private void updateConstruction(Construction[] updateRecords) {
        for (Construction construction : updateRecords) {
            // 修改联系人
            updateById(construction);
        }
    }

    private void deleteConstruction(String chooseId, Construction[] removeRecords) {
        for (Construction removeRecord : removeRecords) {

            Map<String, Object> removeMap = new HashMap<>();
            removeMap.put("choose_id", chooseId);
            removeMap.put("construction_id", removeRecord.getId());

            // 根据id删除联系人
            removeById(removeRecord.getId());
            // 删除关联关系
            chooseConstructionService.removeByMap(removeMap);
        }
    }

    private void saveConstruction(String chooseId, Construction[] insertRecords) {
        for (Construction insertRecord : insertRecords) {
            Construction construction = new Construction();
            // 前端会传一个自生成的id，但后端不需要
            BeanUtil.copyProperties(insertRecord, construction, "id");
            // 存储联系人
            save(construction);
            // 存储关联关系
            chooseConstructionService.save(new ChooseConstruction(chooseId, construction.getId()));
        }
    }

    private boolean checkIdCard(List<Construction> list) {
        for (Construction construction : list) {
            if (!RegexUtils.isIdCard(construction.getIdCard())) {
                return false;
            }
        }
        return true;
    }

    private boolean checkSex(List<Construction> list) {
        for (Construction construction : list) {
            if (!RegexUtils.checkSex(construction.getSex())) {
                return false;
            }
        }
        return true;
    }

    private boolean checkPhone(List<Construction> list) {
        for (Construction construction : list) {
            if (!RegexUtils.isMobile(construction.getPhone())) {
                return false;
            }
        }
        return true;
    }

}